package step

import (
	"github.com/wanchain/go-mpc/log"
	"github.com/wanchain/go-mpc/p2p/discover"
	mpcprotocol "github.com/wanchain/go-mpc/storeman/storemanmpc/protocol"
	"math/big"
)

type RequestMpcStepBtc struct {
	BaseStep
	messageType      int64
	accType          []byte
	txHash           big.Int
	address          big.Int
	chainID          big.Int
	chainType        []byte
	signType         []byte
	txCode           []byte
	message          map[discover.NodeID]bool
	peerCount        uint16
	curveTypeBytes   []byte
	gpkBytes         []byte
	mpcSignByApprove []big.Int
}

func (req *RequestMpcStepBtc) InitStep(result mpcprotocol.MpcResultInterface) error {
	log.SyslogDebug("RequestMpcStep.InitStep begin")

	if req.messageType == mpcprotocol.MpcGPKLeader {
		return nil

	} else if req.messageType == mpcprotocol.MpcSignLeaderBtc {
		addr, err := result.GetValue(mpcprotocol.MpcAddress)
		if err != nil {
			return err
		}

		req.address = addr[0]
		req.chainType, err = result.GetByteValue(mpcprotocol.MpcChainType)
		if err != nil {
			return err
		}

		req.signType, err = result.GetByteValue(mpcprotocol.MpcSignType)
		if err != nil {
			return err
		}

		req.txCode, err = result.GetByteValue(mpcprotocol.MpcTransaction)
		if err != nil {
			return err
		}

		req.curveTypeBytes, err = result.GetByteValue(mpcprotocol.MpcCurve)
		if err != nil {
			return err
		}

		req.gpkBytes, err = result.GetByteValue(mpcprotocol.MpcGpkBytes)
		if err != nil {
			return err
		}

		req.mpcSignByApprove, err = result.GetValue(mpcprotocol.MpcByApprove)
		if err != nil {
			return err
		}

		if string(req.chainType) != "BTC" {
			hash, err := result.GetValue(mpcprotocol.MpcTxHash + "_0")
			if err != nil {
				return err
			}

			req.txHash = hash[0]
			chainID, err := result.GetValue(mpcprotocol.MpcChainID)
			if err != nil {
				return err
			}

			req.chainID = chainID[0]
		}
	}

	return nil
}

func CreateRequestMpcStepBtc(totalNum int, pc uint16, messageType int64) *RequestMpcStepBtc {
	return &RequestMpcStepBtc{BaseStep: *CreateBaseStep(totalNum, -1),
		messageType: messageType,
		message:     make(map[discover.NodeID]bool),
		peerCount:   pc}
}

func (req *RequestMpcStepBtc) CreateMessage() []mpcprotocol.StepMessage {
	msg := mpcprotocol.StepMessage{
		MsgCode:   mpcprotocol.RequestMPCBtc,
		PeerID:    nil,
		Data:      nil,
		BytesData: nil}
	msg.Data = make([]big.Int, 1)
	msg.Data[0].SetInt64(req.messageType)
	if req.messageType == mpcprotocol.MpcSignLeaderBtc {
		msg.Data = append(msg.Data, req.txHash)
		msg.Data = append(msg.Data, req.address)
		msg.Data = append(msg.Data, req.chainID)
		msg.Data = append(msg.Data, *big.NewInt(0).SetUint64(uint64(req.peerCount)))
		msg.Data = append(msg.Data, req.mpcSignByApprove[0])

		msg.BytesData = make([][]byte, 5)
		msg.BytesData[0] = req.chainType
		msg.BytesData[1] = req.txCode
		msg.BytesData[2] = req.signType
		msg.BytesData[3] = req.curveTypeBytes
		msg.BytesData[4] = req.gpkBytes

	} else if req.messageType == mpcprotocol.MpcGPKLeader {
		msg.BytesData = make([][]byte, 1)
		msg.BytesData[0] = req.accType
	}

	return []mpcprotocol.StepMessage{msg}
}

func (req *RequestMpcStepBtc) FinishStep(result mpcprotocol.MpcResultInterface, mpc mpcprotocol.StoremanManager) error {
	err := req.BaseStep.FinishStep()
	if err != nil {
		return err
	}

	data := make([]big.Int, 1)
	data[0].SetInt64(req.messageType)
	result.SetValue(mpcprotocol.MPCAction, data)
	return nil
}

func (req *RequestMpcStepBtc) HandleMessage(msg *mpcprotocol.StepMessage) bool {
	log.SyslogInfo("RequestMpcStep.HandleMessage begin, peerID:%s", msg.PeerID.String())
	_, exist := req.message[*msg.PeerID]
	if exist {
		log.SyslogErr("RequestMpcStep.HandleMessage, get message from peerID fail. peer:%s", msg.PeerID.String())
		return false
	}

	req.message[*msg.PeerID] = true
	return true
}
